#include <iostream>
#include <windows.h>
#include <tlhelp32.h>

DWORD GetProcessIdByName(std::string processName) {
    DWORD processId = 0;
    processName = processName.substr(processName.find_last_of('\\')+1);
    processName = processName.substr(0, processName.find('.'));
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot!= INVALID_HANDLE_VALUE) {
        PROCESSENTRY32 processEntry;
        processEntry.dwSize = sizeof(processEntry);
        if (Process32First(snapshot, &processEntry)) {
            do {
                if (processName == processEntry.szExeFile) {
                    processId = processEntry.th32ProcessID;
                    break;
                }
            } while (Process32Next(snapshot, &processEntry));
        }
        CloseHandle(snapshot);
    }
    return processId;
}
int main(int args,char** argv) {
    HANDLE hProc = 0;
    int id = GetProcessIdByName(argv[1]);
    if(id==0){
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        ZeroMemory(&pi, sizeof(pi));
        if (!CreateProcess(NULL, argv[1], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
            std::cerr << "Failed to start subprocess." << std::endl;
            return 1;
        }
        WaitForSingleObject(hProc, INFINITE);
        hProc = pi.hProcess;
    }else{
        hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
        if (!hProc) {
            std::cerr << "Failed to open target process." << std::endl;
            return 1;
        }
    }
    std::string filepath = "apicall.dll";
    LPVOID lpAddr =  VirtualAllocEx(hProc,NULL, filepath.size(), MEM_COMMIT, PAGE_READWRITE);
    if(!lpAddr) {
        CloseHandle(hProc);
        std::cout << "alloc memory fail"<<std::endl;
        return 1;
    }
	WriteProcessMemory(hProc, lpAddr, filepath.c_str(), filepath.size(), NULL);
	HMODULE sysMod = LoadLibraryA("Kernel32.dll");
    if(!sysMod){
        VirtualFreeEx(hProc, lpAddr, 0, MEM_RELEASE);
        CloseHandle(hProc);
        std::cout << "load kernel dll fail"<<std::endl;
        return 1;
    }else{
        LPTHREAD_START_ROUTINE fp =(LPTHREAD_START_ROUTINE) GetProcAddress(sysMod, "LoadLibraryA");
        HANDLE hThread = CreateRemoteThread(hProc, NULL, NULL,(LPTHREAD_START_ROUTINE)fp, lpAddr, 0, NULL);
        if(!hThread) {
            std::cout << "create remote thread fail"<<std::endl;
        }
        WaitForSingleObject(hThread, INFINITE);
        CloseHandle(hThread);

        HMODULE hookMod = LoadLibraryA(filepath.c_str());
        sysMod = GetModuleHandleA(filepath.c_str());
        if(!sysMod){
            VirtualFreeEx(hProc, lpAddr, 0, MEM_RELEASE);
            CloseHandle(hProc);
            std::cout << "load apicall dll fail"<<std::endl;
            return 1;
        }
        fp =(LPTHREAD_START_ROUTINE) GetProcAddress(sysMod, "InitSym");
        hThread = CreateRemoteThread(hProc, NULL, NULL,(LPTHREAD_START_ROUTINE)fp, 0, 0, NULL);
        if(!hThread) {
            std::cout << "create remote thread fail"<<std::endl;
        }
        WaitForSingleObject(hThread, INFINITE);
        CloseHandle(hThread);
        FreeLibrary(hookMod);
    }
    VirtualFreeEx(hProc, lpAddr, 0, MEM_RELEASE);
    CloseHandle(hProc);
    return 0;
}